using System;
using Framework.Core.CommandLine;
using Framework.Core.Io;
using Framework.Core.Process;
using log4net;

namespace Framework.Core.BootStrapper.WindowsService
{
    public abstract class WindowsServicePlugin<TArgs> : IPlugin<TArgs>, IWindowsService<TArgs>
        where TArgs : WindowsServiceArgs
    {
        private readonly IProcessController processController;
        private readonly IServiceBaseAdapter serviceBaseAdapter;
        private readonly IConsoleAdapter consoleAdapter;
        private readonly ICommandLineParser commandLineParser;

        private static readonly ILog Logger = LogManager.GetLogger(typeof(WindowsServicePlugin<TArgs>));

        protected WindowsServicePlugin()
            : this(new ProcessController(), new ServiceBaseAdapter(), new ConsoleAdapter(), new CommandLineParser())
        {

        }

        internal WindowsServicePlugin(IProcessController processController, IServiceBaseAdapter serviceBaseAdapter, IConsoleAdapter consoleAdapter, ICommandLineParser commandLineParser)
        {
            this.processController = processController;
            this.serviceBaseAdapter = serviceBaseAdapter;
            this.consoleAdapter = consoleAdapter;
            this.commandLineParser = commandLineParser;
        }

        public int Execute(string[] args)
        {
            var deploymentArgs = commandLineParser.Parse<WindowsServiceArgs>(args);

            if (deploymentArgs.IsInstallMode)
            {
                try
                {
                    commandLineParser.Parse<TArgs>(new[] { deploymentArgs.Args });
                }
                catch (ArgumentException)
                {
                    Logger.ErrorFormat(@"invalid arguments {0}, add /a like /a{{/firstArgs:value,/secondArgs:value}}", deploymentArgs.Args);
                    return -1;
                }

                processController.Install(deploymentArgs);
                return 0;
            }

            if (deploymentArgs.IsUninstallMode)
            {
                processController.Uninstall(deploymentArgs);
                return 0;
            }

            return Execute(commandLineParser.Parse<TArgs>(args));
        }

        public int Execute(TArgs args)
        {
            if (args.IsConsoleMode)
            {
                Start(args);
                consoleAdapter.Read();
                Stop();
                return 0;
            }

            serviceBaseAdapter.Run(this, args);
            return 0;
        }

        public abstract void Start(TArgs args);

        public abstract void Stop();
    }
}